﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Consulta;
using System.Configuration;
using System.Xml;
using System.IO;
using System.Collections;
using HotelORTExcepciones;

namespace Dominio
{
    public class Sistema : ISistema
    {
        private IConsultas consultas;
        private int idUsuarioLogueado;
        
        #region Singleton Sistema

        private static Sistema instancia = null;
        

        #endregion

        private Sistema()
        {
            consultas = FactoryConsulta.getInstanceConsulta();
        }
        

        public void login(string usuario, string password)
        {
            try
            {
                string encriptada = Encriptacion.Encrypt(password);
                consultas.validarUsuario(usuario, encriptada);
                idUsuarioLogueado = obtenerIdUsuario(usuario);
            }
            catch (Exception e)
            {
                throw new UsuarioNoValidadoException("Usuario o Password incorrecto.",e);
            }
        }

        public static Sistema getInstance()
        {
            if (instancia == null)
            {
                instancia = new Sistema();
            }
            return instancia;
        }

        // Altas

        public int altaUsuario(string usuario, string password, string Nombre, string Apellido, DateTime Nacimiento, char estado)
        {
            try
            {
                string encriptada = Encriptacion.Encrypt(password);   
                int n= consultas.altaUsuario(usuario, encriptada, Nombre, Apellido, Nacimiento, estado);
                    return 0;
            }catch(Exception e)
            {
                throw e;
            }
        }

        public void modificarUsuario(int idUsuario,string usuario, string password, string Nombre, string Apellido, DateTime Nacimiento, char estado)
        {
            try
            {
                consultas.modificarUsuario(idUsuario, usuario, password, Nombre, Apellido, Nacimiento, estado);
            }
            catch (Exception e)
            {
                throw e;
            }

        }

        public int altaHabitacion(int numero, string capacidad, string categoria, List<int> lstcom, char estado)
        {
            try
            {
                return consultas.agregarHabitacion(numero, capacidad, categoria, lstcom, estado);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int altaCategoria(string nombre, string descripcion, char est)
        {
            try
            {
                return consultas.agregarCategoria(nombre, descripcion, est);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int altaComodidad(string txtCom, string desc, float costoAgregado, char estado)
        {
            try
            {
                return consultas.agregarComodidad(txtCom, desc, costoAgregado, estado);
                    
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int altaCliente(string nombre, string apellido, string tel)
        {
            try
            {
                return consultas.agregarCliente(nombre,apellido,tel);

            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int altaRol(string nombre, char estado)
        {
            try
            {
                return consultas.altaRol(nombre, estado);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public int altaPermiso(string desc)
        {
            try
            {
                return consultas.altaPermiso(desc);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public void agregarLog(DateTime fecha, int idusuario, string accion, string clasificacion)
        {
            try
            {
                consultas.agregarLog(fecha, idusuario, accion, clasificacion);
            }
            catch (Exception e)
            {
                throw e;
            }

        }

        public int realizarReserva(int idCliente, int numeroHab, DateTime fchin, DateTime fchout)
        {
            return consultas.realizarReserva(idCliente, numeroHab, fchin, fchout);
        }

        public bool realizarCheckIn(int idReserva)
        {
            return consultas.realizarCheckIn(idReserva);
        }

        

        // Modificaciones

        public void modificarHabitacion(int idHabitacion, string capacidad, string categoria, List<int> listaComodidades, char estado)
        {
            try
            {
                int idcategoria=0;
                foreach(string[] cat in consultas.traerCategorias(true))
                {
                    if (cat[1] == categoria)
                    {
                        idcategoria = int.Parse(cat[0]);
                        break;
                    }
                }
                consultas.modificarHabitacion(idHabitacion, capacidad, idcategoria, listaComodidades, estado);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        
        public void modificarCategoria(int idCategoria, string nombre, string descripcion, char est)
        {
            try
            {
                consultas.modificarCategoria(idCategoria, nombre, descripcion, est);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void modificarRol(int id, string nombre, char estado)
        {
            try
            {
                consultas.updateRol(id, nombre, estado);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void modificarPermiso(int id, string desc)
        {
            consultas.updatePermiso(id, desc);
        }

        public void modificarComodidad(int idComodidad, string nombre, string descripcion, float costoExtra,char est)
        {
            try
            {
                consultas.modificarComodidad(idComodidad, nombre, descripcion, costoExtra, est);
            }
            catch (Exception e)
            {
                throw e;
            }

        }

        public void modificarCliente(int idCliente, string nombre, string apellido, string tel)
        {
            try
            {
                consultas.modificarCliente(idCliente, nombre, apellido, tel);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        // Consultas

        //public List<String[]>   consultarLog(DateTime fch)
        //{
        //    List<string[]> lst = new List<string[]>();
        //    lst = consultas.DarLogsFecha(fch);
        //    return lst;
        //}

        public string[] traerCliente(int idCliente)
        {
            try
            {
                return consultas.traerCliente(idCliente);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public bool             existeReserva(int idReserva)
        {
            try
            {
            return consultas.existeReserva(idReserva);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public List<String[]>   traerClientes()
        {
            try
            {
            return consultas.traerClientes();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public List<String[]> traerComodidades(bool soloactivos)
        {
            try
            {
            return consultas.traerComodidades(soloactivos);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public List<String[]> traerCategorias(bool soloactivos)
        {
            try
            {
                return consultas.traerCategorias(soloactivos);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public List<String[]> traerRoles()
        {
            try
            {
                return consultas.traerRoles();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public List<String[]> traerPermisos()
        {
            try
            {
                return consultas.traerPermisos();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public float traerCostoHabitacion(int idcat, string cap)
        {
            return 0;
            //return consultas.traerCostoHabitacion(idcat, cap);
        }

        public List<string[]> obtenerUsuarios()
        {
            return consultas.obtenerUsuarios();

        }

        public void agregarCostoHabitacion(int idCategoria, string capacidad, float costo)
        {
            try
            {
                consultas.AgregarCostoHabitacion(idCategoria, capacidad, costo);
            }catch(Exception e)
            {
                throw e;
            }
        }

        

        //public void AgregarCostoHabitacion(int idcat, string cap, float precio)
        //{
        //    consultas.AgregarCostoHabitacion(idcat, cap, precio);
        //}

        public List<String[]> traerHabitaciones(bool soloactivos)
        {
            try
            {
                return consultas.obtenerHabitaciones(soloactivos);
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        public List<string[]>   obtenerComodidadesHabitacion(int numero)
        {
            try
            {
                return consultas.obtenerComodidadesHabitacion(numero);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public float            obtenerCostoHabitacion(int cate, string cap)
        {
            try
            {
                return consultas.traerCostoHabitacion(cate, cap);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public List<string[]> DarHabitacionesDisponibles(string ini, string fin, List<int> listcomodidades, int idcat, string cap)
        {
            //try
            //{
                return consultas.DarHabitacionesDisponibles(ini, fin, listcomodidades, idcat, cap);
            //}
            //catch (Exception e)
            //{
            //    throw e;
           // }
        }
        public int calcularCantidadDeNoches(int hab)
        {
            return consultas.calcularCantidadDeNoches(hab);
        }

        public double calcularAlojamiento(int hab)
        {
            return consultas.costoHabitacion(hab);
        }

        public List<String> traerExtras()
        {
            return consultas.traerExtras();
        }

        public void realizarCheckOut(int h)
        {
            consultas.realizarCheckOut(h);
        }

        public List<string> traerNumeroDeHabitacionesOcupadas()
        {
            return consultas.obtenerHabitacionesOcupadas();
        }

        public string traerClienteDeUnaHabitacion(int habitacionActual)
        {
            return consultas.traerClienteHabitacion(habitacionActual);
        }

        public double calcularCostoDeComodidadesDeUnaHabitacion(int hab)
        {
            List<string[]> lista = new List<string[]>();
            lista = obtenerComodidadesHabitacion(hab);
            double aux = 0;
            foreach (string[] array in lista)
            {
                aux = aux + double.Parse(array[3]);
            }
            return aux;
        }


        public void cambiarPasswordUsuario(int iduser, string password)
        {
            string encriptada = Encriptacion.Encrypt(password);
            consultas.cambiarPasswordUsuario(iduser, encriptada);
        }

        public void validarPasswordUsuario(int iduser, string pass)
        {
            try
            {
                List<string[]> listUsers = consultas.obtenerUsuarios();
                bool encontrado = false;
                foreach (string[] user in listUsers)
                {
                    if (int.Parse(user[0]) == iduser)
                    {
                        if (!Encriptacion.Encrypt(pass).Equals(user[4]))
                            throw new UsuarioNoValidadoException("La password actual ingresada no es la correcta.");
                        else
                        {
                            encontrado = true;
                            break;
                        }
                    }
                }
                if (!encontrado)
                    throw new UsuarioNoValidadoException("No se encontro el IdUsuario.");

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //public int traeUsuario(string usu)
        //{
        //    return consultas.traeUsuario(usu);
        //}

        public void guardarConfiguracion(string nombreHotel, int idPais , string tipoFacturacion, string urlWebService)
        {
            //guardo configuarcion de Facturacion
            try
            {
                // Guardamos la conf de Facturacion en un archivo de conf
                System.Xml.XmlDocument configXml = new System.Xml.XmlDocument();
                configXml.Load("config.xml");
                configXml.ChildNodes[1].ChildNodes[0].FirstChild.InnerText = tipoFacturacion;
               
                if (tipoFacturacion.Equals("Api"))
                {
                    configXml.ChildNodes[1].ChildNodes[0].ChildNodes[1].InnerText = "";
                }
                else
                {
                    configXml.ChildNodes[1].ChildNodes[0].ChildNodes[1].InnerText = urlWebService;
                }
                  
                configXml.Save("config.xml");

                // Y el resto de los datos en la bd.
                consultas.guardarConfiguracion(nombreHotel, idPais);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public string[] getConfiguracionSistema()
        {
            try
            {

                string[] confBD = new string[4];
                confBD[0] = consultas.obtenerConfiguracion()[0];
                confBD[1] = consultas.obtenerConfiguracion()[1];
                confBD[2] = getSistemaActualFacturacion();
                confBD[3] = getWsUrl();
                return confBD;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    
        public List<string[]> traerPermisosUsuario(int usuario)
        {
            return consultas.traerPermisosUsuario(usuario);
        }
        public int altaImpuesto(int idPais, string impuesto, float valor, int orden, char estado)
        {
            try
            {
                return consultas.altaImpuesto(idPais,impuesto,valor,orden,estado);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<String[]> traerImpuestos(int idPais, bool soloactivos)
        {
            try
            {
                return consultas.obtenerImpuestosPais(idPais, soloactivos);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            
        }

        public List<String[]> obtenerPaises(bool soloactivos)
        {
            return consultas.obtenerPaises(soloactivos);
        }

        public void modificarPais(int idPais, string nombre, char estado)
        {
            try
            {
                consultas.modificarPais(idPais, nombre, estado);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public int altaPais(string nombre, char estado)
        {
            try
            {
                return consultas.altaPais(nombre, estado);   
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }


        public void modificarImpuesto(int p, string p_2, float p_3, char estado)
        {
            throw new NotImplementedException();
        }

        public void modificarCategoria(int p, string p_2, char estado)
        {
            throw new NotImplementedException();
        }

        public object altaCategoria(string p, char estado)
        {
            throw new NotImplementedException();
        }

        public String getSistemaActualFacturacion()
        {
            try
            {
                System.Xml.XmlDocument configXml = new System.Xml.XmlDocument();
                configXml.Load("config.xml");

                return configXml.GetElementsByTagName("SistemaFacturacion")[0].InnerText;
            }
            catch (FileNotFoundException f)
            {
                throw new Exception("No se encontro el archivo de configuracion de Facturacion.", f);

            }
        }

        #region Miembros de ISistema


        public string getWsUrl()
        {
            try
            {
                System.Xml.XmlDocument configXml = new System.Xml.XmlDocument();
                configXml.Load("config.xml");

                return configXml.GetElementsByTagName("WebServiceFacturacion")[0].InnerText;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        public bool facturar(string[] conceptos, double[] montos, string cliente, DateTime dateTime)
        {
            FacturaCreator      c = new FacturaCreator();
            ContextoFacturador cf = new ContextoFacturador(c.FactoryMethod());
                                    
            double subtotal = 0;
            
            foreach (double item in montos)
            {
                subtotal = subtotal + item;
            }

            ICalculoImpuestoPais      imp        = CalculoImpuestosFactory.getCalculoImpuestosInstance();
            Dictionary<String, float> listadoImp = imp.calcularImpuestos(subtotal);

            List<String> listaImpuestos = conceptos.ToList();
            List<Double> listaValores = montos.ToList();

            foreach (var item in listadoImp)
            {
                listaImpuestos.Add(item.Key);
                listaValores.Add((double)item.Value);
            }

            return cf.facturar(listaImpuestos.ToArray(), listaValores.ToArray(), cliente, dateTime);
        }

        public void setOrdenImpuesto(int idImpuesto, int orden)
        {
            try
            {
                consultas.setOrdenImpuesto(idImpuesto, orden);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public int getIdPaisConfigurado()
        {
            try
            {
                return consultas.obtenerIdPaisConfigurado();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public int obtenerIdUsuario(string nomUsuario)
        {
            try
            {
                foreach (string[] user in consultas.obtenerUsuarios())
                {
                    if (user[3].Trim() == nomUsuario)
                        return int.Parse(user[0]);
                }
                throw new Exception("No se pudo obtener el idUsuario del usuario " + nomUsuario);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public int obtenerIdUsuarioLogueado()
        {
            if (idUsuarioLogueado != null)
                return idUsuarioLogueado;
            else
                throw new Exception("No se pudo obtener el IdUsuario del usuario Logueado.");
        }

        public string[] obtenerReserva(int nroReserva)
        {
            try
            {
                List<string[]> listReservas = consultas.obtenerReservas();
                foreach (string[] res in listReservas)
                {
                    if (int.Parse(res[0]) == nroReserva)
                        return res;
                }
                throw new NoExisteReservaException("No existe la reserva de numero: " + nroReserva.ToString());

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<string[]> obtenerReservas()
        {
            try
            {
                return consultas.obtenerReservas();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<string[]>  obtenerReservasCheckInFecha(DateTime fechaCheckIn, string estado)
        {
            List<string> estadosPosibles = new List<string>();
            estadosPosibles.Add("Reservado");
            estadosPosibles.Add("Ingresado");
            estadosPosibles.Add("Egresado");
            if (!estadosPosibles.Contains(estado))
                throw new NoExisteEstadoException("No existe el estado: " + estado);
            try
            {
                List<string[]> listReservas = consultas.obtenerReservas();
                List<string[]> listResultado = new List<string[]>();
                foreach (string[] reserva in listReservas)
                {
                    if (reserva[3].Equals(estado)) 
                      if (System.DateTime.Parse(reserva[1]).ToShortDateString().Equals(fechaCheckIn.ToShortDateString()))
                      {
                         listResultado.Add(reserva);
                      }
                }

                return listResultado;
            }catch(Exception ex)
            {
                throw ex;
            }
            
        }
    }
}
